﻿using System;
using UnityEngine;
using Pool;


namespace Test
{
    using System.Collections.Generic;
    using System.Collections;
    using UnityPool;
    using System.Runtime.InteropServices.WindowsRuntime;

    public enum AsyncStatus
    {
        Waiting,
        Loading,
        Finish
    }

    //info
    public class LoadInfo
    {

    }

    public class Loader : MonoBehaviour
    {
        int maxFrameCount = 10;
        private void Update()
        {
            int num = 0;
            if (num < maxFrameCount)
            {
                num++;
                AsyncOption option = AssetPool.Instance.deQueue();
                option.isDone();
            }
        }

    }

    public interface AsyncOption
    {
        bool isDone();
    }

    //asset
    public class AsyncAsset<T> : AsyncOption where T : UnityEngine.Object
    {
        T result;
        string resName;
        bool isAsync;
        public bool IsAsync
        {
            get
            {
                return this.isAsync;
            }
            set
            {
                if (this.isAsync != value)
                {
                    this.isAsync = value;
                    if (this.isAsync)
                    {
                        LoadThread.Instance.StartCoroutine(load());
                    }
                }
            }
        }
        AsyncBundle bundle;
        AssetBundleRequest request;
        AsyncStatus asyncStatus = AsyncStatus.Waiting;
        public Action<T> callBack;

        public AsyncAsset(string resName, bool isAsync, AsyncBundle bundle)
        {
            this.resName = resName;
            this.isAsync = isAsync;
            this.bundle = bundle;
        }

        public bool isDone()
        {
            if (!bundle.isDone())
            {
                return false;
            }
            else
            {
                switch (asyncStatus)
                {
                    case AsyncStatus.Waiting:
                        LoadThread.Instance.StartCoroutine(load());
                        break;
                    case AsyncStatus.Loading:
                        if (this.request.isDone)
                        {
                            this.result = this.request.asset as T;
                            if (this.callBack != null)
                            {
                                this.callBack(this.result);
                            }
                            asyncStatus = AsyncStatus.Finish;
                        }
                        break;
                }
            }
            return asyncStatus == AsyncStatus.Finish;
        }

        IEnumerator load()
        {
            if (!this.isAsync)
            {
                this.result = bundle.Bundle.LoadAsset<T>(this.resName);
                if (this.callBack != null)
                {
                    this.callBack(this.result);
                }
                asyncStatus = AsyncStatus.Finish;
                yield break;
            }
            else
            {
                this.request = bundle.Bundle.LoadAssetAsync<T>(this.resName);
                yield return this.request;
            }
        }
    }

    //bundle
    public class AsyncBundle
    {
        string resUrl;
        public string ResUrl
        {
            get
            {
                return this.resUrl;
            }
        }
        bool isAsync;
        AsyncStatus asyncStatus = AsyncStatus.Waiting;
        AssetBundle bundle;
        public AssetBundle Bundle
        {
            get
            {
                return this.bundle;
            }
        }
        AssetBundleCreateRequest request;
        List<AsyncBundle> depends = null;
        public int refCount = 0;

        public AsyncBundle(string url, bool isAsync)
        {
            this.resUrl = url;
            this.isAsync = isAsync;
            //初始化依赖
            string[] deps = ManifestMgr.getDeps(url);
            if (deps != null)
            {
                depends = new List<AsyncBundle>();
                for (int i = 0; i < deps.Length; i++)
                {
                    AsyncBundle depBundle = AssetPool.Instance.getBundle(deps[i]);
                    if (depBundle == null)
                    {
                        depBundle = new AsyncBundle(deps[i], isAsync);
                        AssetPool.Instance.addBundle(depBundle);
                    }
                    depends.Add(depBundle);
                }
            }

        }

        public bool isDone()
        {
            //1.依赖完成
            if (depends != null)
            {
                for (int i = 0; i < depends.Count; i++)
                {
                    if (!depends[i].isDone())
                    {
                        return false;
                    }
                }
            }
            switch (asyncStatus)
            {
                case AsyncStatus.Waiting:
                    LoadThread.Instance.StartCoroutine(load());
                    break;
                case AsyncStatus.Loading:
                    if (this.request.isDone)
                    {
                        this.bundle = this.request.assetBundle;
                        asyncStatus = AsyncStatus.Finish;
                    }
                    break;
            }
            return asyncStatus == AsyncStatus.Finish;
        }

        IEnumerator load()
        {
            if (!this.isAsync)
            {
                this.bundle = AssetBundle.LoadFromFile(this.resUrl);
                asyncStatus = AsyncStatus.Finish;
                yield break;
            }
            else
            {
                this.request = AssetBundle.LoadFromFileAsync(this.resUrl);
                yield return this.request;
            }

        }

        public AsyncAsset<T> loadAsset<T>(string resName, bool isAsync = true) where T : UnityEngine.Object
        {
            AsyncAsset<T> asyncAsset = new AsyncAsset<T>(resName, isAsync, this);
            AssetPool.Instance.enQueue(asyncAsset);
            return asyncAsset;
        }
    }

    public class AssetPool : Singleton<AssetPool>
    {
        Dictionary<string, AsyncBundle> map = new Dictionary<string, AsyncBundle>();
        Queue<AsyncOption> loadQueue = new Queue<AsyncOption>();

        public void enQueue(AsyncOption asyncOption)
        {
            loadQueue.Enqueue(asyncOption);
        }
        public AsyncOption deQueue()
        {
            return loadQueue.Dequeue();
        }

        public AsyncAsset<T> loadAsset<T>(string resUrl, string resName, bool isAsync = true) where T : UnityEngine.Object
        {
            AsyncBundle asyncBundle;
            if (!map.TryGetValue(resUrl, out asyncBundle))
            {
                asyncBundle = new AsyncBundle(resUrl, isAsync);
                addBundle(asyncBundle);
            }
            return asyncBundle.loadAsset<T>(resName, isAsync);
        }

        public void addBundle(AsyncBundle bundle)
        {
            bundle.isDone();
            map.Add(bundle.ResUrl, bundle);
        }

        public AsyncBundle getBundle(string resUrl)
        {
            AsyncBundle bundle;
            if (map.TryGetValue(resUrl, out bundle))
            {
                return bundle;
            }
            return null;
        }

        public bool hasBundle(string resUrl)
        {
            return map.ContainsKey(resUrl);
        }
    }


    public class Dog
    {
        public GameObject root;
        public void init()
        {
            AssetPool.Instance.loadAsset<Texture2D>("地址", "名称").callBack = loadFinish;
        }

        private void loadFinish(Texture2D go)
        {

        }

    }




}

public class man : PoolObject
{
    public int age = 0;
    public string name = "man";
}

public class woman : PoolObject
{
    public int money = 1;
    public string son = "woman";
}

public class TestClass : MonoBehaviour
{
    public int num = 0;
    private bool isStart = false;
    private double time = 0;

    private void Start()
    {
        Application.targetFrameRate = 120;
    }


    private void Update()
    {
        Application.targetFrameRate = 120;
        if (Input.GetKeyDown(KeyCode.P))
        {
            isStart = true;
            num = 0;
            time = TimerUtils.getMillTimer();
        }
        if (isStart)
        {
            if (TimerUtils.getMillTimer() - time >= 1000)
            {
                Debug.LogError(num);
                isStart = false;
                return;
            }
            num++;

        }

    }


}

